<?php

App::uses('AppModel', 'Model');

/**
 * Organisation Model
 *
 * @property OrganisationType $OrganisationType
 * @property Member $Member
 * @property OrganisationAccount $OrganisationAccount
 * @property OrganisationContributionType $OrganisationContributionType
 * @property OrganisationAnniversary $OrganisationAnniversary
 * @property OrganisationGroupType $OrganisationGroupType
 * @property OrganisationSubscription $OrganisationSubscription
 */
class Organisation extends AppModel {
    //The Associations below have been created with all possible keys, those that are not needed can be removed

    public $useDbConfig = "organisations";
    
    /**
     * belongsTo associations
     *
     * @var array
     */
    public $belongsTo = array(
        'OrganisationType' => array(
            'className' => 'OrganisationType',
            'foreignKey' => 'organisation_type_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );

    /**
     * hasMany associations
     *
     * @var array
     */
    public $hasMany = array(
        'OrganisationAccount' => array(
            'className' => 'OrganisationAccount',
            'foreignKey' => 'organisation_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
        'OrganisationContributionType' => array(
            'className' => 'OrganisationContributionType',
            'foreignKey' => 'organisation_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
        'OrganisationAnniversary' => array(
            'className' => 'OrganisationAnniversary',
            'foreignKey' => 'organisation_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
        'OrganisationGroupType' => array(
            'className' => 'OrganisationGroupType',
            'foreignKey' => 'organisation_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
        'OrganisationSubscription' => array(
            'className' => 'OrganisationSubscription',
            'foreignKey' => 'organisation_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
        'OrganisationSetting' => array(
            'className' => 'OrganisationSetting',
            'foreignKey' => 'organisation_id',
            'dependent' => false
        ),
        'OrganisationMember' => array(
            'className' => 'OrganisationMember',
            'foreignKey' => 'organisation_id',
            'dependent' => false
        ),
        'OrganisationRole' => array(
            'className' => 'OrganisationRole',
            'foreignKey' => 'organisation_id',
            'dependent' => false
        ),
        'OrganisationCounter' => array(
            'className' => 'OrganisationCounter',
            'foreignKey' => 'organisation_id',
            'dependent' => false
        ),
        'OrganisationMemberCategory' => array(
            'className' => 'OrganisationMemberCategory',
            'foreignKey' => 'organisation_id',
            'dependent' => false
        ),
        'OrganisationMemberCategorySetting' => array(
            'className' => 'OrganisationMemberCategorySetting',
            'foreignKey' => 'organisation_id',
            'dependent' => false
        )
    );
    
    public $hasAndBelongsToMany = array(
        'Module' => array(
            'className' => 'Module',
            'joinTable' => 'organisation_modules',
            'foreignKey' => 'organisation_id',
            'associationForeignKey' => 'module_id',
            'unique' => true,
            'conditions' => 'Module.active = 1 AND OrganisationModule.active = 1',
            'dependent' => false
        )
    );
    
    /**
     * Creates a new organisation
     * 
     * @param type $organisation
     * @param type $member
     */
    public function createOrganisation($account) {
        
        // validate an organisation can be created with the specified account information
        /*$response = $this->OrganisationAccount->checkAvailability(-1, $account['account.username']);
        
        if( $response['status'] == 'unavailable' ) {
            return $response;
        }*/
        
        // generate a new pass salt
        /*$pass_salt = rand(10000, 99999);
        $member_id = null;
        
        // determine if a member profile exists with the supplied email address
        $Member = ClassRegistry::init('Member');        
        $profile = $Member->getProfileByEmail($account['email']);
        
        // if no profile exists, create a new one and associate the organisation with it
        if( !$profile ) {
            //return array('status' => 'failed', 'message' => 'Account cannot be created. Email already in use');
            
            // member account
            $memberData = array(
                'Member' => array(
                    'first_name' => $account['first_name'],
                    'last_name' => $account['last_name'],
                    'gender' => $account['gender'],
                    'dob' => $account['dob'],
                    'email' => $account['email'],
                    'active' => 1
                ),
                'MemberAccount' => array(
                    array(
                        'username' => $account['account.username'],
                        'password' => md5($account['account.password'] . $pass_salt),
                        'pass_salt' => $pass_salt,
                        'active' => 0
                    )
                )
            );

            $Member->saveAll($memberData);

            $member_id = $Member->id;
        }
        
        // use the existing profile id for the connection
        else {
            $member_id = $profile['Member']['id'];
        }*/
        
        $member_account = ClassRegistry::init('MemberAccount')->find('count', array(
            'conditions' => array(
                'MemberAccount.id' => $account['member_account_id']
            )
        ));
        
        if( !$member_account ) {
            return array('status' => 'failed', 'message' => 'Invalid member account information supplied');
        }
        
        // set up data to create organisation    
        $orgData = array(
            'Organisation' => array(
                'name' => $account['name'],
                'slug' => $account['slug'] . '-' . rand(10000,99999), // generated ensure slug is always unique. users can change later
                'address'=>$account['address'],
                'organisation_type_id' => $account['organisation_type_id'],
                'email' => $account['email'],
                'phone' => $account['phone'],
                'city' => $account['city'],
                'country' => $account['country'],
                'post_code' => $account['post_code'],
                'state' => $account['state'],
                'website' => $account['website'],
                'active' => 1
            ),
            'OrganisationSubscription' => array(
                array(
                    'subscription_type_id' => $account['subscription.type_id'],
                    'start_dt' => date('Y-m-d H:i:s'),
                    'end_dt' => date('Y-m-d H:i:s',strtotime("+1 month")),
                )
            )
        );
        
        // create the organisation
        $this->saveAll($orgData);
        // get the new id
        $organisation_id = $this->id;

        // generate the settings
        $settings = $this->populateSettings($organisation_id, $account['member_account_id']);

        // associate the member with the organisation
        $this->OrganisationMember->createDefaultMember($organisation_id, $account['member_account_id'], $settings, $account);


        return array(
            'status' => 'success',
            'organisation_id' => $organisation_id,
            'organisation_account_id' => $settings['default_account_id']
        );
    }

    /**
     * Return an organisation that exists for the specified email address
     * 
     * @param type $email
     * @return type
     */
    public function getOrganisationByEmail($email) {
        return $this->find('first', array(
            'conditions' => array(
                'Organisation.email' => $email,
                'Organisation.active' => 1
            ),
            'recursive' => -1
        ));
    }

    public function getOrganisationInfo($organisation_id, $contain = array()) {
        
        if( empty($contain) ) {
            $contain = array(
                'OrganisationType',
                'OrganisationAnniversary' => array(
                    'conditions' => array('active' => 1, 'organisation_id' => $organisation_id),
                    'order' => array('name')
                ), 
                'OrganisationGroupType' => array(
                    'conditions' => array('active' => 1, 'organisation_id' => $organisation_id),
                    'OrganisationGroup' => array(
                        'conditions' => array('active' => 1, 'organisation_id' => $organisation_id),
                        'order' => array('name')
                    )
                )
            );
        }
        
        $organisation = $this->find('first', array(
            'contain' => $contain,
            'conditions' => array(
                'or' => array(
                    'Organisation.id' => $organisation_id,
                    'Organisation.slug' => $organisation_id
                )
            )
        ));
        
        if( $organisation ) {
            $organisation['Organisation']['members'] = $this->OrganisationMember->getTotalMembers($organisation['Organisation']['id']);
            
            return $organisation;
        }
        
        return array('status' => 'failed', 'message' => 'Organisation not found for id specified');
    }

    /**
     * Ver crud profile save approach
     * 
     * TODO: improve this functionality to include validations
     * 
     * @param type $organisation_id
     * @param type $info
     * @return type
     */
    public function updateProfile($organisation_id, $info) {
        
        $this->id = $organisation_id;
        
        return $this->saveAll($info);
    }
    
    public function getSettings($organisation_id) {
        $data = $this->OrganisationSetting->find('all', array(
            'conditions' => array(
                'OrganisationSetting.organisation_id' => $organisation_id
            )
        ));
        
        $settings = array();
        
        foreach($data as $setting) {
            $settings[ $setting['SettingType']['name'] ] = $setting['OrganisationSetting']['value'];
        }
        
        return $settings;
    }
    
    public function populateSettings($organisation_id, $member_account_id) {
        
        // create modules
        $modules = $this->Module->populateDefault($organisation_id);
        
        // create general settings and preferences
        $settings_done = $this->OrganisationSetting->createDefault($organisation_id);
        
        // create counters
        $counters_done = $this->OrganisationCounter->createDefault($organisation_id);
        
        // create organisation roles
        $role_data = $this->OrganisationRole->createDefault($organisation_id, $member_account_id);
        
        // create categories
        $default = $this->OrganisationMemberCategory->populateDefault($organisation_id);
        
        
        // get default user
        //$default_account_id = $this->OrganisationAccount->getDefaultAccount($organisation_id);
        
        return array(
            'settings' => $settings_done, 
            'counters' => $counters_done, 
            'default_role_id' => $role_data['organisation_role_id'],
            'default_category' => $default,
            'modules' => $modules,
            'default_account_id' => $role_data['organisation_account_id']
        );
    }
    
    public function publicList($member_id, $offset = 0, $limit = 10) {
        
        $sql = "SELECT organisations.*, ot.name as `type`, discoverable.value as discoverable, public_join.value as public_join, count(om.id) as members FROM organisations "
                . "INNER JOIN organisation_types ot ON ot.id = organisations.organisation_type_id "
                . "INNER JOIN organisation_settings discoverable ON discoverable.organisation_id = organisations.id AND discoverable.setting_type_id = 6 "
                . "INNER JOIN organisation_settings public_join ON public_join.organisation_id = organisations.id AND public_join.setting_type_id = 4 "
                . "LEFT JOIN organisation_members om ON om.organisation_id = organisations.id "
                . "LEFT JOIN organisation_members omc ON omc.organisation_id = organisations.id AND omc.member_id = $member_id "
                . "WHERE omc.member_id IS NULL "
                . "GROUP BY organisations.id "
                . "LIMIT $offset, $limit ";
        
        $organisations = $this->query($sql);
        
        foreach($organisations as &$organisation) {
            $new_org = array();
            foreach($organisation as $key => $data) {
                $new_org = array_merge($new_org, $data);
            }
            
            $organisation = $new_org;
        }
        
        return $organisations;
    }
    
    public function activate($organisation_id, $activate) {
        
        $updated = $this->updateAll(array('Organisation.active' => $activate), array('Organisation.id' => $organisation_id));
        
        if( $updated ) {
            $organisation = $this->find('first', array(
                'conditions' => array('Organisation.id' => $organisation_id)
            ));
            
            return array('status' => 'success', 'message' => 'Organisation updated successfully', 'active' => $activate, 'Organisation' => $organisation['Organisation']);
        }
        
        else {
            return array('status' => 'failed', 'message' => 'Organisation update failed');
        }
    }
    
    /**
     * Removes the organisation from the system and schedules it for deletion
     * 
     * @param type $organisation_id
     * @param type $member_account_id
     * @return type
     */
    public function remove($organisation_id, $member_account_id) {
        $account = $this->OrganisationAccount->find('first', array(
            'contain' => array(
                'OrganisationRole'
            ),
            'conditions' => array(
                'OrganisationAccount.organisation_id' => $organisation_id,
                'OrganisationAccount.member_account_id' => $member_account_id,
                'OrganisationRole.admin_access' => 1
            )
        ));
        
        if( !$account ) {
            return array('status' => 'failed', 'message' => 'Authorized organisation account not found');
        }
        
        // if this role has admin access
        if( !$account['OrganisationRole']['admin_access'] ) {
            return array('status' => 'failed', 'message' => 'Your account does not have the permission to remove this organisation.');
        }
        
        // save the changes
        $this->save(array(
            'id' => $organisation_id,
            'active' => 0,
            'trashed' => 1
        ));
        
        return array('status' => 'success', 'message' => 'The organisation has been successfully removed. All data will remain available for the next 30 days and can be restored before then. The account will be completely removed after that time');
    }
}
